package ldh.im.fxgui.controller.sub;

import com.jfoenix.controls.JFXDialog;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import ldh.im.dto.enums.MessageType;
import ldh.im.fxbase.dao.ImSessionDao;
import ldh.im.fxbase.data.pojo.ImMessage;
import ldh.im.fxbase.data.pojo.ImSession;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.service.ImGroupService;
import ldh.im.fxbase.service.ImSessionService;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.component.cell.UserIconView;
import ldh.im.fxgui.service.MessageSendService;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.fxgui.util.UserHeadImageUtil;
import org.controlsfx.control.PopOver;
import org.fxmisc.flowless.Cell;
import org.fxmisc.flowless.VirtualFlow;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.kordamp.ikonli.fontawesome.FontAwesome;
import org.kordamp.ikonli.javafx.FontIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 聊天-》会话-》消息-》消息转发-》创建会话并转发
 */
public class TransferMessageWithUserController extends TransferBaseController implements Initializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(TransferMessageWithUserController.class);

    @FXML private TextField searchTextField;
    @FXML private StackPane userContainer;
    @FXML private ScrollPane selectedUserScrollPane;
    @FXML private VBox selectedUserContainer;

    @FXML private TextField leaveMessageTextField;
    @FXML private Button sendMessageBtn;
    @FXML private Label selectedUserNum;

    private JFXDialog parentDialg;

    private ObservableList<WrapUser> items = FXCollections.observableArrayList();
    private FilteredList<WrapUser> filteredData = new FilteredList<>(items, s -> true);
    private SortedList<WrapUser> sortedList = new SortedList<>(filteredData, this::userComparator);
    private VirtualFlow<WrapUser, ?> sessionListView;
    private VirtualizedScrollPane virtualizedScrollPane = null;
    private PopOver popOver = new PopOver();

    private Set<ImUser> selectImUsers = new HashSet<>();
    private Map<Long, Pane> selectedPaneMap = new HashMap<>();

    private ImSessionDao imSessionDao = BeanFactory.getInstance().getBean(ImSessionDao.class);
    private ImSessionService imSessionService = BeanFactory.getInstance().getBean(ImSessionService.class);
    private ImGroupService imGroupService = BeanFactory.getInstance().getBean(ImGroupService.class);
    private MessageSendService messageSendService = BeanFactory.getInstance().getBean(MessageSendService.class);

    public void setParentDialog(JFXDialog parentDialg) {
        this.parentDialg = parentDialg;
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        sessionListView = VirtualFlow.createVertical(sortedList, m->{
            return Cell.wrapNode(createPane(m));
        });
        virtualizedScrollPane = new VirtualizedScrollPane<>(sessionListView);
        userContainer.getChildren().setAll(virtualizedScrollPane);

        loadData();

        searchTextField.textProperty().addListener(l->{
            String searchText = searchTextField.getText().trim();
            filteredData.setPredicate(wrapUser -> wrapUser.getImUser().getUserName().contains(searchText));
        });

        selectedUserContainer.getChildren().addListener((InvalidationListener)l->{
            if (selectedUserContainer.getChildren().size() < 1) {
                sendMessageBtn.setDisable(true);
            } else {
                sendMessageBtn.setDisable(false);
            }
            int size = selectedUserContainer.getChildren().size();
            size = size > 5 ? 5 : size;
            selectedUserScrollPane.setPrefHeight(45 * size);
            selectedUserNum.setText(selectedUserContainer.getChildren().size() + "");
        });

        sendMessageBtn.setDisable(false);

        selectedUserScrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
    }

    @FXML
    private void transferMessage(ActionEvent actionEvent) {
        if (selectImUsers.size() < 1) return;
        ThreadPoolUtil.submit(()->{
            ExceptionUtil.catchException(()->{
                String loginUserId = UiUtil.getLoginImUser().getUserId();
                ImSession imSession = null;
                if (selectImUsers.size() == 1) {
                    ImUser toUser = selectImUsers.iterator().next();
                    imSession = imSessionDao.getByUserId(loginUserId, loginUserId, toUser.getUserId());
                    if(imSession == null) {
                        imSession = imSessionService.createSession(loginUserId, toUser);
                    }
                } else {
                    selectImUsers.add(ImCacheFactory.getInstance().getUser(loginUserId));
                    imSession = imGroupService.buildImGroup(loginUserId, selectImUsers);
                    imGroupService.createImGroup(imSession);
                    imGroupService.rpcCreateGroup(imSession);
                }
                List<ImMessage> messages = new ArrayList<>();
                messages.addAll(buildTransferMessage(imSession));
                messages.addAll(buildLeaveMessage(imSession));
                ImSession finalSession = imSession;
                FxThreadUtil.runLater(()->{
                    Task task = messageSendService.sendMessage(finalSession, messages);
                    task.setOnSucceeded(e->{
                        if (task.getProgress()>=0.3) { // 本地保存成功
                            UiUtil.uiShowMessages(messages);
                            if (selectImUsers.size() == 1) {
                                UiUtil.switchMessageSession(finalSession);
                            }
                        }
                    });
                });
                return null;
            }, "转发消息");
            FxThreadUtil.runLater(()-> {
                close(null);
                parentDialg.close();
            });
        });
    }



    private void loadData() {
        ThreadPoolUtil.submit(()-> {
            try{
                List<ImUser> imUserList = ImCacheFactory.getInstance().getAllUsers();
                List<WrapUser> wrapUsers = imUserList.stream().map(WrapUser::new).collect(Collectors.toList());
                FxThreadUtil.runLater(()-> {
                    items.addAll(wrapUsers);
                    sessionListView.show(0);
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private int userComparator(WrapUser user1, WrapUser user2) {
        if (user1.getImUser().getUpdateTime() == null) return -1;
        if (user2.getImUser().getUpdateTime() == null) return 1;
        return user1.getImUser().getUpdateTime().compareTo(user2.getImUser().getUpdateTime());
    }

    private Node createPane(WrapUser wrapUser) {
        HBox hBox = new HBox();
        hBox.getStyleClass().add("select-user-item");
        hBox.setAlignment(Pos.CENTER_LEFT);
        hBox.setSpacing(10);

        RadioButton selectRadio = new RadioButton();
        selectRadio.selectedProperty().bindBidirectional(wrapUser.selectPropertyProperty());

        selectRadio.selectedProperty().addListener((l, o, n)-> selectUser(hBox, wrapUser.getImUser(), selectRadio));
        hBox.getChildren().add(selectRadio);

        hBox.setOnMouseClicked(e->{
            selectRadio.setSelected(!selectRadio.isSelected());
        });

        if (selectImUsers.contains(wrapUser.getImUser())) {
            selectRadio.setSelected(true);
            hBox.getStyleClass().add("selected");
        }

        ImageView imageView = new UserIconView(wrapUser.getImUser());
        imageView.setFitHeight(40);
        imageView.setFitWidth(40);
        hBox.getChildren().add(imageView);

        Label tipLabel = new Label(wrapUser.getImUser().getUserName());
        tipLabel.setTooltip(new Tooltip(wrapUser.getImUser().getUserName()));
        hBox.getChildren().add(tipLabel);

        return hBox;
    }

    private void selectUser(HBox hBox, ImUser imUser, RadioButton selectRadio) {
        if (selectRadio.isSelected()) {
            if (selectImUsers.contains(imUser)) return;
            hBox.getStyleClass().add("selected");
        } else if(selectImUsers.contains(imUser)){
            Pane pane = selectedPaneMap.remove(imUser.getId());
            selectedUserContainer.getChildren().remove(pane);
            selectImUsers.remove(imUser);

            hBox.getStyleClass().remove("selected");
            return;
        }

        Pane pane = createSelectedUserPane(imUser, selectRadio);
        selectedUserContainer.getChildren().add(pane);
        selectedUserScrollPane.setVvalue(1);
        selectImUsers.add(imUser);
        selectedPaneMap.put(imUser.getId(), pane);
    }

    private Pane createSelectedUserPane(ImUser imUser, RadioButton selectRadio) {
        HBox hBox = new HBox();
        hBox.getStyleClass().add("selected-user-item");
        hBox.setUserData(imUser);

        ImageView imageView = new UserIconView(imUser);
        imageView.setFitHeight(40);
        imageView.setFitWidth(40);
        hBox.getChildren().add(imageView);

        Label tipLabel = new Label(imUser.getUserName());
        tipLabel.setTooltip(new Tooltip(imUser.getUserName()));

        Region region = new Region();
        HBox.setHgrow(region, Priority.ALWAYS);

        Label closeLabel = new Label();
        closeLabel.getStyleClass().add("close-label");

        FontIcon fontIcon = FontIcon.of(FontAwesome.CLOSE);
        fontIcon.setIconColor(Color.WHITE);

        closeLabel.setGraphic(fontIcon);
        closeLabel.setAlignment(Pos.CENTER);
        closeLabel.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        hBox.getChildren().addAll(tipLabel, region, closeLabel);

        closeLabel.setOnMouseEntered(e-> fontIcon.setIconColor(Color.GRAY));
        closeLabel.setOnMouseExited(e-> fontIcon.setIconColor(Color.LIGHTGRAY));
        closeLabel.setOnMouseClicked(e->{
            selectRadio.setSelected(false);
        });
        return hBox;
    }

    private List<ImMessage> buildLeaveMessage(ImSession imSession) {
        String text = leaveMessageTextField.getText().trim();
        List<ImMessage> result = new ArrayList<>();
        if (text.equals("")) return result;
        if (selectImUsers.size() < 1) return result;

        ImMessage message = messageSendService.buildMessage(imSession, text, MessageType.Text, (ImMessage)null);
        message.setImSession(imSession);
        result.add(message);

        return result;
    }

    private class WrapUser {
        private ImUser imUser;
        private BooleanProperty selectProperty = new SimpleBooleanProperty(false);

        public WrapUser(ImUser imUser) {
            this.imUser = imUser;
        }

        public ImUser getImUser() {
            return imUser;
        }

        public boolean isSelectProperty() {
            return selectProperty.get();
        }

        public BooleanProperty selectPropertyProperty() {
            return selectProperty;
        }

        public void setSelectProperty(boolean selectProperty) {
            this.selectProperty.set(selectProperty);
        }
    }

}
